package com.yuyou.weixin.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.yuyou.weixin.common.CommEnum;
import com.yuyou.weixin.common.WexinException;
import com.yuyou.weixin.entity.*;
import com.yuyou.weixin.mapper.AnswerMapper;
import com.yuyou.weixin.mapper.AnswerResultRelMapper;
import com.yuyou.weixin.mapper.TestResultMapper;
import com.yuyou.weixin.service.IAnswerService;
import com.yuyou.weixin.util.BeanUtils;
import com.yuyou.weixin.util.WeixinUtil;
import com.yuyou.weixin.vo.AnswerVo;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * @Author: weiwenfeng
 * @Date: 2018/6/14
 */
@Service
public class AnswerServiceImpl implements IAnswerService {

    private Logger log = LoggerFactory.getLogger(AnswerServiceImpl.class);

    @Autowired
    private AnswerMapper answerMapper;

    @Autowired
    private TestResultMapper testResultMapper;


    @Autowired
    private AnswerResultRelMapper answerResultRelMapper;

    @Override
    @Transactional
    public List<TestResult> insertAnswer(AnswerVo answerVo) throws Exception{
        Answer answer = new Answer();
        answer.setCreateTime(new Date());
        BeanUtils.copyProperties(answer, answerVo);
        answerMapper.insertAnswer(answer);

        String[] jobs = answerVo.getJobs().split(",");
        List<TestResult> testResults = new ArrayList<>();
        for (String job : jobs) {
            Map<String, Float> subjectWeightMap = initWeightMap();
            // 根据分数计算权重
            calWeightByScore(subjectWeightMap, answerVo);
            // 根据科目排序计算权重
            calWeightBySubjectSort(subjectWeightMap, answerVo);
            // 根据职业计算权重
            calWeightByJob(subjectWeightMap, answerVo, job);
            // 根据社团计算权重
            calWeightByAssociation(subjectWeightMap, answerVo);
            // 根据权重排序
            List<SubjectWeight> subjectWeights = sortSubjectByWeight(subjectWeightMap);
            TestResult testResult = new TestResult();
            testResult.setJob(job);
            testResult.setSubjectComb(getSubjectComb(subjectWeights));
            testResult.setSubjectScoreJson(JSON.toJSONString(subjectWeights));
            setPlan(answerVo, testResult);
            testResult.setCreateTime(new Date());
            testResultMapper.insertResult(testResult);
            testResults.add(testResult);
        }
        insertRels(answer, testResults);
        return testResults;
    }

    /**
     * 将答案和结果关联关系插入数据库
     *
     * @param answer
     * @param testResults
     */
    private void insertRels(Answer answer, List<TestResult> testResults) {
        int answerId = answer.getAnswerId();
        List<Integer> resultIds = BeanUtils.toList(testResults, "resultId");
        List<AnswerResultRel> answerResultRels = new ArrayList<>();
        for (Integer resultId : resultIds) {
            AnswerResultRel rel = new AnswerResultRel();
            rel.setAnswerId(answerId);
            rel.setResultId(resultId);
            answerResultRels.add(rel);
        }
        answerResultRelMapper.insertRels(answerResultRels);
    }

    /**
     * 获取排名前三的科目
     *
     * @param subjectWeights
     * @return
     */
    private String getSubjectComb(List<SubjectWeight> subjectWeights) {
        List<String> subjects = BeanUtils.toList(subjectWeights, "subject");
        subjects = subjects.subList(0, 3);
        String subjectComb = Joiner.on("+").join(subjects);
        return subjectComb;
    }

    /**
     * 根据科目权重排序,权重大的靠前
     *
     * @param subjectWeightMap
     * @return
     */
    private List<SubjectWeight> sortSubjectByWeight(Map<String, Float> subjectWeightMap) {
        List<SubjectWeight> subjectWeights = new ArrayList<>();
        for (String subject : subjectWeightMap.keySet()) {
            float weight = subjectWeightMap.get(subject);
            SubjectWeight subjectWeight = new SubjectWeight();
            subjectWeight.setSubject(subject);
            subjectWeight.setWeight(weight);
            subjectWeights.add(subjectWeight);
        }
        bubbleSort(subjectWeights);
        return subjectWeights;
    }

    /**
     * 冒泡排序
     *
     * @param subjectWeights
     */
    private void bubbleSort(List<SubjectWeight> subjectWeights) {
        SubjectWeight temp;
        for (int i = 0; i < subjectWeights.size() - 1; i++) {
            for (int j = 0; j < subjectWeights.size() - 1 - i; j++) {
                if (subjectWeights.get(j).getWeight() < subjectWeights.get(j + 1).getWeight()) {
                    temp = subjectWeights.get(j);
                    subjectWeights.set(j, subjectWeights.get(j + 1));
                    subjectWeights.set(j + 1, temp);
                }
            }
        }
    }

    /**
     * 设置学生规划
     *
     * @param answerVo
     * @param testResult
     */
    private void setPlan(AnswerVo answerVo, TestResult testResult) {
        String content = WeixinUtil.getStringFromFile("stu_plan.json");
        JSONObject studentPlanJson = JSONObject.parseObject(content);
        float score = answerVo.getScore();
        JSONObject jsonObject;
        if (score >= 720) {
            jsonObject = (JSONObject) studentPlanJson.get("720或以上");
        } else {
            jsonObject = (JSONObject) studentPlanJson.get("720以下");
        }
        String word1 = getWord(jsonObject, 1);
        //String word2 = getWord(jsonObject, 2);
        String word3 = getWord(jsonObject, 3);
        testResult.setPlan(word1 + word3);
    }

    private String getWord(JSONObject jsonObject, int index) {
        String wordStr = (String) jsonObject.get(index);
        String[] words = wordStr.split("\\|");
        Random random = new Random();
        int ran = random.nextInt(words.length);
        //从|分割的句子中随机抽取一句话
        String word = words[ran];
        return word;
    }


    /**
     * 初始化权重
     *
     * @return
     */
    private Map<String, Float> initWeightMap() {
        Map<String, Float> subjectWeightMap = new HashMap<>();
        subjectWeightMap.put(CommEnum.subject.WULI.getValue(), 5.0f);
        subjectWeightMap.put(CommEnum.subject.HUAXUE.getValue(), 5.0f);
        subjectWeightMap.put(CommEnum.subject.SHENGWU.getValue(), 5.0f);
        subjectWeightMap.put(CommEnum.subject.ZHENGZHI.getValue(), 5.0f);
        subjectWeightMap.put(CommEnum.subject.LISHI.getValue(), 5.0f);
        subjectWeightMap.put(CommEnum.subject.DILI.getValue(), 5.0f);
        return subjectWeightMap;
    }

    /**
     * 根据分数计算权重
     *
     * @param subjectWeightMap
     * @param answerVo
     */
    private void calWeightByScore(Map<String, Float> subjectWeightMap, AnswerVo answerVo) {
        float score = answerVo.getScore();
        String subjectStr = answerVo.getSubjects();
        subjectStr = subjectStr.replace(",", "");
        if (score >= 720) {
            Float weight = subjectWeightMap.get(CommEnum.subject.WULI.getValue());
            int rank = subjectStr.indexOf(CommEnum.subject.WULI.getValue()) / 2 + 1;
            if (rank == 1 || rank == 2) {
                weight += 4;
            }
            if (rank == 3 || rank == 4) {
                weight += 2;
            }
            subjectWeightMap.put(CommEnum.subject.WULI.getValue(), weight);
        } else if (score >= 700 && score < 720) {
            Float weight = subjectWeightMap.get(CommEnum.subject.HUAXUE.getValue());
            int rank = subjectStr.indexOf(CommEnum.subject.HUAXUE.getValue()) / 2 + 1;
            if (rank == 1 || rank == 2) {
                weight += 4;
            }
            if (rank == 3 || rank == 4) {
                weight += 2;
            }
            subjectWeightMap.put(CommEnum.subject.HUAXUE.getValue(), weight);
        } else if (score >= 680 && score < 700) {
            Float weight1 = subjectWeightMap.get(CommEnum.subject.DILI.getValue());
            subjectWeightMap.put(CommEnum.subject.DILI.getValue(), weight1 + 2);
            Float weight2 = subjectWeightMap.get(CommEnum.subject.SHENGWU.getValue());
            subjectWeightMap.put(CommEnum.subject.SHENGWU.getValue(), weight2 + 2);
        } else {
        }
    }

    /**
     * 根据科目排序计算权重
     *
     * @param subjectWeightMap
     * @param answerVo
     */
    private void calWeightBySubjectSort(Map<String, Float> subjectWeightMap, AnswerVo answerVo) {
        String subjectStr = answerVo.getSubjects();
        String[] subjects = subjectStr.split(",");
        for (int i = 0; i < subjects.length; i++) {
            String subject = subjects[i];
            Float weight = subjectWeightMap.get(subject);
            switch (i) {
                case 0:
                    weight += 3;
                    break;
                case 1:
                    weight += 2.5f;
                    break;
                case 2:
                    weight += 1.5f;
                    break;
                case 3:
                    weight += 0;
                    break;
                case 4:
                    weight -= 2;
                    break;
                case 5:
                    weight -= 3;
                    break;
                default:
                    break;
            }
            subjectWeightMap.put(subject, weight);
        }
    }

    /**
     * 根据职业计算权重
     *
     * @param subjectWeightMap
     * @param answerVo
     */
    private void calWeightByJob(Map<String, Float> subjectWeightMap, AnswerVo answerVo, String job) {
        Map<String, Float> tempMap = new HashMap<>();
        if (job.indexOf("会计") != -1) {
            tempMap.put(CommEnum.subject.LI.getValue(), 1f);
        } else if (job.indexOf("翻译") != -1) {
            tempMap.put(CommEnum.subject.WEN.getValue(), 1f);
        } else if (job.indexOf("新闻传播") != -1) {
            tempMap.put(CommEnum.subject.WEN.getValue(), 1f);
        } else if (job.indexOf("律师") != -1) {
            String subject = getPreviousSubject(answerVo, CommEnum.subject.ZHENGZHI.getValue(), CommEnum.subject.LISHI.getValue());
            tempMap.put(subject, 10f);
        } else if (job.indexOf("文科老师") != -1) {
            tempMap.put(CommEnum.subject.WEN.getValue(), 2f);
        } else if (job.indexOf("理科老师") != -1) {
            tempMap.put(CommEnum.subject.LI.getValue(), 2f);
        } else if (job.indexOf("档案管理") != -1) {
            String subject = getPreviousSubject(answerVo, CommEnum.subject.ZHENGZHI.getValue(), CommEnum.subject.LISHI.getValue());
            tempMap.put(subject, 10f);
        } else if (job.indexOf("计算机") != -1) {
            String subject = getPreviousSubject(answerVo, CommEnum.subject.WULI.getValue(), CommEnum.subject.HUAXUE.getValue());
            tempMap.put(subject, 10f);
        } else if (job.indexOf("建筑") != -1) {
            tempMap.put(CommEnum.subject.WULI.getValue(), 10f);
        } else if (job.indexOf("机械") != -1) {
            String subject = getPreviousSubject(answerVo, CommEnum.subject.WULI.getValue(), CommEnum.subject.HUAXUE.getValue());
            tempMap.put(subject, 10f);
        } else if (job.indexOf("化工") != -1) {
            String subject = getPreviousSubject(answerVo, CommEnum.subject.WULI.getValue(), CommEnum.subject.HUAXUE.getValue());
            tempMap.put(subject, 10f);
        } else if (job.indexOf("科学育种") != -1) {
            String subject = getPreviousSubject(answerVo, CommEnum.subject.SHENGWU.getValue(), CommEnum.subject.WULI.getValue());
            tempMap.put(subject, 10f);
        } else if (job.indexOf("护理") != -1) {
            String subject = getPreviousSubject(answerVo, CommEnum.subject.WULI.getValue(), CommEnum.subject.HUAXUE.getValue());
            tempMap.put(subject, 10f);
        } else if (job.indexOf("人力资源") != -1) {
            tempMap.put(CommEnum.subject.WEN.getValue(), 1f);
            tempMap.put(CommEnum.subject.LI.getValue(), 1f);
        } else if (job.indexOf("物流") != -1) {
            tempMap.put(CommEnum.subject.SHENGWU.getValue(), 1f);
            tempMap.put(CommEnum.subject.HUAXUE.getValue(), 1f);
            tempMap.put(CommEnum.subject.WULI.getValue(), 2f);
        } else if (job.indexOf("设计师") != -1) {
            tempMap.put(CommEnum.subject.WEN.getValue(), 1f);
        } else if (job.indexOf("导演") != -1) {
            tempMap.put(CommEnum.subject.WEN.getValue(), 1f);
            tempMap.put(CommEnum.subject.LI.getValue(), 1f);
        } else if (job.indexOf("城乡规划") != -1) {
            String subject = getPreviousSubject(answerVo, CommEnum.subject.WULI.getValue(), CommEnum.subject.DILI.getValue());
            tempMap.put(subject, 10f);
        } else {

        }
        addWeight(tempMap, subjectWeightMap);
    }

    /**
     * 根据社团计算权重
     *
     * @param subjectWeightMap
     * @param answerVo
     */
    private void calWeightByAssociation(Map<String, Float> subjectWeightMap, AnswerVo answerVo) {
        String association = answerVo.getAssociation();
        Map<String, Float> tempMap = new HashMap<>();
        if (association.indexOf("辩论") != -1) {
            tempMap.put(CommEnum.subject.WEN.getValue(), 1f);
            tempMap.put(CommEnum.subject.WULI.getValue(), 1f);
        } else if (association.indexOf("机器人社") != -1) {
            tempMap.put(CommEnum.subject.WULI.getValue(), 2f);
            tempMap.put(CommEnum.subject.HUAXUE.getValue(), 1f);
            tempMap.put(CommEnum.subject.SHENGWU.getValue(), 1f);
        } else if (association.indexOf("金融社") != -1) {
            tempMap.put(CommEnum.subject.ZHENGZHI.getValue(), 1f);
            tempMap.put(CommEnum.subject.LISHI.getValue(), 1f);
        } else if (association.indexOf("学生会") != -1) {
            tempMap.put(CommEnum.subject.WEN.getValue(), 1f);
            tempMap.put(CommEnum.subject.LI.getValue(), 1f);
        } else if (association.indexOf("足球社") != -1) {
            tempMap.put(CommEnum.subject.WEN.getValue(), 1f);
            tempMap.put(CommEnum.subject.LI.getValue(), 1f);
        } else if (association.indexOf("摄影社") != -1) {
            tempMap.put(CommEnum.subject.WEN.getValue(), 1f);
            tempMap.put(CommEnum.subject.LI.getValue(), 1f);
        } else {
            tempMap.put(CommEnum.subject.WEN.getValue(), 1f);
        }
        addWeight(tempMap, subjectWeightMap);
    }

    /**
     * 获取两个科目中排名靠前的
     *
     * @param answerVo
     * @param subject1
     * @param subject2
     * @return
     */
    private String getPreviousSubject(AnswerVo answerVo, String subject1, String subject2) {
        String subjectStr = answerVo.getSubjects();
        subjectStr = subjectStr.replace(",", "");
        int rank1 = subjectStr.indexOf(subject1) / 2 + 1;
        int rank2 = subjectStr.indexOf(subject2) / 2 + 1;
        return rank1 < rank2 ? subject1 : subject2;
    }

    /**
     * 添加权重
     *
     * @param temMap
     * @param subjectWeightMap
     */
    private void addWeight(Map<String, Float> temMap, Map<String, Float> subjectWeightMap) {
        for (String key : temMap.keySet()) {
            if (key.equals(CommEnum.subject.WEN.getValue())) {
                List<String> subjects = getWen();
                for (String subject : subjects) {
                    addWeighToMap(subjectWeightMap, subject, temMap.get(key));
                }
            } else if (key.equals(CommEnum.subject.LI.getValue())) {
                List<String> subjects = getLi();
                for (String subject : subjects) {
                    addWeighToMap(subjectWeightMap, subject, temMap.get(key));
                }
            } else {
                addWeighToMap(subjectWeightMap, key, temMap.get(key));
            }
        }
    }

    private void addWeighToMap(Map<String, Float> subjectWeightMap, String subject, Float weight) {
        Float totalWeight = subjectWeightMap.get(subject);
        if (null == totalWeight) {
            totalWeight = 0f;
        }
        totalWeight += weight;
        subjectWeightMap.put(subject, totalWeight);
    }

    /**
     * 获取理理科科目
     *
     * @return
     */
    private List<String> getLi() {
        List<String> subjects = new ArrayList<>();
        subjects.add(CommEnum.subject.WULI.getValue());
        subjects.add(CommEnum.subject.HUAXUE.getValue());
        subjects.add(CommEnum.subject.SHENGWU.getValue());
        return subjects;
    }

    /**
     * 获取文科科目
     *
     * @return
     */
    private List<String> getWen() {
        List<String> subjects = new ArrayList<>();
        subjects.add(CommEnum.subject.ZHENGZHI.getValue());
        subjects.add(CommEnum.subject.LISHI.getValue());
        subjects.add(CommEnum.subject.DILI.getValue());
        return subjects;
    }

    @Override
    public List<AnswerHis> queryAnswerHis(String unionid) {
        return answerMapper.queryAnswerHis(unionid);
    }
}
